using FoundationLib.AddIns.Constraints.Resources;
using FoundationLib.AddIns.Constraints.Visitors;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FoundationLib.AddIns.Constraints
{
	/// <summary>
	/// Performs the transformation of OCL statements attached to methods or classes
	/// into C# code
	/// </summary>
	public class OclTransformer
	{
		/// <summary>
		/// A list of OCL statements subject to transformation
		/// </summary>
		private IEnumerable<OclStatement> statements;
		/// <summary>
		/// A set of visitors performing transformations on specific OCL statements
		/// </summary>
		private SortedList<int, IVisitor> visitors;

		/// <summary>
		/// Creates a new OCL transformer
		/// </summary>
		private OclTransformer()
		{
			this.visitors = new SortedList<int, IVisitor>();
			this.RegisterVisitors();
		}

		/// <summary>
		/// Registers a set of supported visitors
		/// </summary>
		private void RegisterVisitors()
		{
			this.visitors.Add(0, new CollectionLoopVisitor());
			this.visitors.Add(1, new ComplexCollectionVisitor());
			this.visitors.Add(2, new CollectionVisitor());
			this.visitors.Add(3, new InfixVisitor());
			this.visitors.Add(4, new PrimitivesVisitor());
		}

		/// <summary>
		/// Performs the transformation on all extracted OCL statements
		/// </summary>
		/// <returns>A list of C# statements representing the extracted OCL
		/// statements</returns>
		public IEnumerable<string> Transform()
		{
			foreach (OclStatement statement in this.statements)
			{
				foreach (KeyValuePair<int, IVisitor> item in this.visitors)
				{
					statement.Accept(item.Value);
				}
			};

			return this.statements.Select((x) => {
				string result = null;
				string format = null;

				if (x is ClassOclStatement)
				{
					format = FormatManager.GetFormat("Inv");
				}
				else if (x is MethodOclStatement)
				{
					MethodOclStatement stmt = x as MethodOclStatement;
					if (stmt.ConstraintType == MethodConstraintType.PreCondition)
						format = FormatManager.GetFormat("Pre");
					else if (stmt.ConstraintType == MethodConstraintType.PostCondition)
						format = FormatManager.GetFormat("Post");
				}

				result = String.Format(format, x.Value + (!String.IsNullOrWhiteSpace(x.Name) ? ", \"" + x.Name + "\"" : ""));
				return result;
			});
		}

		/// <summary>
		/// Creates a new OCL transformer
		/// </summary>
		/// <param name="statements">The statements to transform</param>
		public OclTransformer(IEnumerable<OclStatement> statements)
			: this()
		{
			if (statements == null)
				throw new ArgumentNullException("statements");
			this.statements = statements;
		}
	}
}
